package cn.qianxun.meta.auth.thirdlogin.util;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * @Author fuzhilin
 * @Date 2022/6/20 0020 10:37
 * @Description
 */
public class AuthTokenUtil {
    public static void main(String[] args) {
        String code = "e94845f6b1e9481c9f993ca1fb4861ea";
        String accessKey = "a882b3642a36493c90819f514aed1c2d";
        String email = "yyAdmin";
        Long timestamp = System.currentTimeMillis();
        System.out.println(timestamp);
        //生成authToken
        String authToken = AuthTokenUtil.generateAuthToken(accessKey, timestamp, code, email);
        String authToken2 = AuthTokenUtil.generateAuthToken(accessKey, timestamp, code, email);
        System.out.println("authToken：" + authToken);
        System.out.println("authToken2：" + authToken2);

        //email加密
        String encodeEmail = AuthTokenUtil.encryptContent(email, accessKey);
        System.out.println("加密后邮箱：" + encodeEmail);
        //email解密
        String decodeEmail = AuthTokenUtil.decryptContent(encodeEmail, accessKey);
        System.out.println("解密后邮箱：" + decodeEmail);
        System.out.println("http://127.0.0.1:8080/thrid/index.html?token=" + authToken + "&m=" + encodeEmail + "&t=" + timestamp);

    }


    /**
     * 生成authToken
     *
     * @param accessKey 密钥
     * @param timestamp 时间戳
     * @param code      产品编码，暂定是域名
     * @param email     email，未加密
     * @return
     */
    public static String generateAuthToken(String accessKey, Long timestamp, String code, String email) {
        String key = accessKey + timestamp;
        String content = code + email + timestamp;
        String accessToken = generateResponseBodySignature(key, content);
        return accessToken;
    }

    /**
     * 默认编码：UTF-8
     */
    private static final String CHARSET = "UTF-8";


    /**
     * 获取请求体签名
     *
     * @param key  accessKey
     * @param body 待签名的body体字符串
     * @return 生成的签名
     */
    public static String generateResponseBodySignature(String key, String body) {
        return base_64(hmacSHA256(key, body));
    }

    public static byte[] hmacSHA256(String macKey, String macData) {
        try {
            SecretKeySpec secret = new SecretKeySpec(macKey.getBytes(CHARSET), "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(secret);
            return mac.doFinal(macData.getBytes(CHARSET));
        } catch (UnsupportedEncodingException | InvalidKeyException | NoSuchAlgorithmException e) {
            //error message log
            return new byte[0];
        }
    }

    /**
     * 加密字符串，使用AES-CBC方式进行加密
     *
     * @param accessKey 密钥
     * @param content   待加密内容
     * @return 加密后内容
     */
    public static String encryptContent(String content, String accessKey) {
        String iv = getRandomChars(16);
        //密钥长度128位
        int keySize = 128;
        String isvEncryptBody = encryptAESCBCEncode(content, accessKey, iv, keySize);
        return iv + isvEncryptBody;
    }

    /**
     * AES CBC 128位加密
     *
     * @param content 加密内容
     * @param key     加密秘钥
     * @param iv      加密盐值
     * @return 加密结果
     */
    public static String encryptAESCBCEncode(String content, String key, String iv, int keySize) {

        if (StringUtils.isEmpty(content) || StringUtils.isEmpty(key) || StringUtils.isEmpty(iv)) {
            return null;
        }

        try {
            byte[] encrypContent = encryptAESCBC(content.getBytes(CHARSET), key.getBytes(CHARSET), iv.getBytes(CHARSET), keySize);
            if (null != encrypContent) {
                return base_64(encrypContent);
            } else {
                return null;
            }

        } catch (UnsupportedEncodingException e) {
            //error message log
            return null;
        }
    }

    public static byte[] encryptAESCBC(byte[] content, byte[] keyBytes, byte[] iv, int keySize) {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(keyBytes);
            keyGenerator.init(keySize, secureRandom);
            SecretKey key = keyGenerator.generateKey();
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
            return cipher.doFinal(content);
        } catch (Exception e) {
            //error message log
            return null;
        }
    }

    public static String base_64(byte[] bytes) {

        try {
            return new String(Base64.encodeBase64(bytes), CHARSET);
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    public static String decryptContent(String encryptStr, String accessKey) {
        if (StringUtils.isEmpty(encryptStr)) {
            return null;
        }
        String iv = encryptStr.substring(0, 16);
        int keySize = 128;
        String decryptBody = null;

        try {
            decryptBody = decryptAESCBCEncode(encryptStr.substring(16), accessKey, iv, keySize);
        } catch (Exception e) {
            //error message log
            return null;
        }

        return decryptBody;
    }

    public static String decryptAESCBCEncode(String content, String key, String iv, int keySize) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {

        if (StringUtils.isEmpty(content) || StringUtils.isEmpty(key) || StringUtils.isEmpty(iv)) {
            return null;
        }

        return new String(decryptAESCBC(Base64.decodeBase64(content.getBytes()), key.getBytes(), iv.getBytes(), keySize));
    }

    public static byte[] decryptAESCBC(byte[] content, byte[] keyBytes, byte[] iv, int keySize) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(keyBytes);
        keyGenerator.init(keySize, secureRandom);
        SecretKey key = keyGenerator.generateKey();
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        return cipher.doFinal(content);
    }

    /**
     * 获取随机字符串
     *
     * @param length 字符串长度
     * @return 随机字符串
     */
    public static String getRandomChars(int length) {
        StringBuilder randomCharsBuf = new StringBuilder(1024);
        SecureRandom random = new SecureRandom();

        for (int i = 0; i < length; i++) {
            // 字母和数字中随机
            if (random.nextInt(2) % 2 == 0) {
                // 输出是大写字母还是小写字母
                int letterIndex = random.nextInt(2) % 2 == 0 ? 65 : 97;
                randomCharsBuf.append((char) (random.nextInt(26) + letterIndex));
            } else {
                randomCharsBuf.append(random.nextInt(10));
            }
        }

        return randomCharsBuf.toString();
    }
}

